#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/kernel.h>	//printk()
#include <linux/random.h>
#include <asm/uaccess.h>	//copy_to_user()
#define BUFF_LEN 20
static char		my_buff[20];
static ssize_t	my_buff_size = sizeof(my_buff);

//loff_t is long long
static ssize_t my_driver_read(struct file* fp, char* buff, size_t len, loff_t* off)
{
	printk("Reading device file at offset =%d, read bytes count %d", (int)*off, (unsigned int)len);
	if(*off == 0)
		get_random_bytes(my_buff, my_buff_size);
	if(*off >= my_buff_size)
		return 0;
	if(*off + len > my_buff_size)
		len = my_buff_size - *off;
	if(raw_copy_to_user(buff, my_buff + *off, len))
		return -EFAULT;
	*off += len;
	return len;
}

static ssize_t my_driver_write(struct file* fp, const char* buff, size_t len, loff_t* off)
{
	return 0;
}

struct file_operations my_deriver_fops = {
	.read = my_driver_read,
	.write = my_driver_write,
};

static int device_file_major_number = 201;
static const char device_name[] = "Simple_driver";

int register_device(void)
{
	int result = 0;
	printk("register_device() is called.\n");
	result = register_chrdev(device_file_major_number, device_name, &my_deriver_fops);
	if(result < 0)
	{
		printk(KERN_WARNING "can't register char device with err num: %d", result);
		return result;
	}
	printk(KERN_NOTICE "successfully registered device with name:%s, major num:%d",
			device_name, device_file_major_number);
	return 0;
}

void unregister_device(void)
{
	printk(KERN_NOTICE "unregister_device() is called.\n");
	unregister_chrdev(device_file_major_number, device_name);
}

static int my_random_kernel_init(void)
{
	printk("Hello kernel init\n");
	return register_device();
}

static void my_random_kernel_exit(void)
{
	printk("Hello kernel exit\n");
	unregister_device();
}

module_init(my_random_kernel_init);
module_exit(my_random_kernel_exit);

MODULE_LICENSE("GPL");

